import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import datetime, timedelta
import numpy as np
import random
import os


# 设置中文显示并忽略字体找不到的异常
def set_chinese_font():
    try:
        plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC", "Arial Unicode MS"]
    except Exception as e:
        # 若指定中文字体失败，直接使用默认字体，不抛出异常
        if "findfont" not in str(e).lower() and "font" not in str(e).lower():
            print(f"字体设置警告: {e}，将使用默认字体")
        plt.rcParams["font.family"] = ["Arial", "Helvetica", "sans-serif"]
    plt.rcParams["axes.unicode_minus"] = False  # 正确显示负号


def plot_and_save_weight_trend(data=None, title="体重变化趋势图"):
    """
    绘制日期-体重折线图（含最高/最低/平均值），并保存为图片到当前目录
    图片名称格式：体重趋势图_YYYYMMDD_HHMMSS.png

    参数:
        data: 字典类型，键为日期字符串(格式'YYYY-MM-DD')，值为体重数值
        title: 图表标题
    """
    set_chinese_font()  # 初始化字体
    try:
        # 1. 处理数据：无自定义数据则生成30天示例数据
        if data is None:
            dates = []
            weights = []
            start_date = datetime.now() - timedelta(days=30)
            for i in range(30):
                current_date = start_date + timedelta(days=i)
                dates.append(current_date.strftime('%Y-%m-%d'))
                # 生成带轻微上升趋势的随机体重（60-75kg）
                base_weight = 65 + i * 0.1
                weights.append(round(base_weight + random.uniform(-1.5, 1.5), 1))
            data = dict(zip(dates, weights))

        # 2. 日期格式转换与排序（确保按时间顺序展示）
        date_objs = [datetime.strptime(date, '%Y-%m-%d') for date in data.keys()]
        weights = list(data.values())
        sorted_pairs = sorted(zip(date_objs, weights), key=lambda x: x[0])
        sorted_dates, sorted_weights = zip(*sorted_pairs)

        # 3. 计算关键统计值
        max_weight = max(sorted_weights)
        min_weight = min(sorted_weights)
        avg_weight = round(np.mean(sorted_weights), 1)
        # 定位最高值、最低值对应的日期
        max_date = sorted_dates[sorted_weights.index(max_weight)]
        min_date = sorted_dates[sorted_weights.index(min_weight)]

        # 4. 创建并配置图表
        fig, ax = plt.subplots(figsize=(12, 6))
        # 绘制体重折线（带圆点标记）
        ax.plot(sorted_dates, sorted_weights, 'o-', color='#4287f5', linewidth=2.5, markersize=6, label='每日体重')
        # 绘制最高/最低/平均值辅助线
        ax.axhline(y=max_weight, color='#ff4444', linestyle='--', alpha=0.8, linewidth=2,
                   label=f'最高值: {max_weight} kg')
        ax.axhline(y=min_weight, color='#22c55e', linestyle='--', alpha=0.8, linewidth=2,
                   label=f'最低值: {min_weight} kg')
        ax.axhline(y=avg_weight, color='#f59e0b', linestyle='-.', alpha=0.8, linewidth=2,
                   label=f'平均值: {avg_weight} kg')

        # 5. 标注最高值和最低值（带箭头指向）
        ax.annotate(f'最高: {max_weight} kg',
                    xy=(max_date, max_weight), xytext=(5, 8), textcoords='offset points',
                    fontsize=10, color='#ff4444', weight='bold',
                    arrowprops=dict(arrowstyle='->', color='#ff4444', alpha=0.8))
        ax.annotate(f'最低: {min_weight} kg',
                    xy=(min_date, min_weight), xytext=(5, -15), textcoords='offset points',
                    fontsize=10, color='#22c55e', weight='bold',
                    arrowprops=dict(arrowstyle='->', color='#22c55e', alpha=0.8))

        # 6. 优化坐标轴与布局
        # X轴：按周显示主刻度，日期标签旋转避免重叠
        ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
        ax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=mdates.MO))  # 每周一为主刻度
        plt.xticks(rotation=45, ha='right', fontsize=10)
        # Y轴：设置标签与字体
        ax.set_ylabel('体重 (kg)', fontsize=11, weight='bold')
        ax.set_xlabel('日期', fontsize=11, weight='bold')
        # 标题与网格
        ax.set_title(title, fontsize=13, weight='bold', pad=20)
        ax.grid(True, linestyle=':', alpha=0.5, color='#999999')
        # 图例（放在右上角，避免遮挡数据）
        ax.legend(loc='upper right', fontsize=9, framealpha=0.9)

        # 7. 保存图片到当前目录
        # 生成含执行时间的图片名称（格式：体重趋势图_20251001_143025.png）
        exec_time = datetime.now().strftime('%Y%m%d_%H%M%S')
        img_name = f"体重趋势图_{exec_time}.png"
        img_path = os.path.join(os.getcwd(), img_name)  # 获取当前目录路径
        # 保存图片（dpi=300确保清晰度，bbox_inches避免标签被截断）
        plt.tight_layout()
        plt.savefig(img_path, dpi=300, bbox_inches='tight', facecolor='white')
        print(f"图表已保存到：{img_path}")

        plt.close()  # 关闭图表，释放内存

    except Exception as e:
        # 仅捕获非字体相关的异常并提示
        if "findfont" not in str(e).lower() and "font" not in str(e).lower():
            print(f"生成图表时出错: {str(e)}")


# 示例用法
if __name__ == "__main__":
    # 方式1：使用自定义体重数据（替换为你的实际数据）
    custom_data = {
        '2023-09-08': 80.7,
        '2023-09-18': 83.7,
        '2023-09-22': 85.7,
        '2023-10-20': 82.6,
        '2023-10-28': 79.0,
        '2023-11-17': 80.0,
        '2023-12-11': 83.7,
        '2023-12-18': 86.8,
        '2023-12-25': 88.2,

        '2024-01-06': 91.0,
        '2024-01-22': 94.0,
        '2024-05-18': 90.4,
        '2024-07-09': 87.0,

        '2025-01-10': 89.0,
        '2025-05-20': 89.0,
        '2025-06-11': 92.0,
        '2025-08-04': 89.8,
        '2025-08-21': 87.8,
        '2025-09-01': 92.4,
        '2025-09-17': 83.0,
        '2025-10-20': 86.0,
    }
    plot_and_save_weight_trend(custom_data, "Zxr的体重变化趋势")

    # 方式2：使用自动生成的30天示例数据（直接运行即可）
    # plot_and_save_weight_trend(title="30天体重变化趋势图")
